home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / audio_output / dec.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  11KB  |  361 lines

  1. /*****************************************************************************
  2.  * dec.c : audio output API towards decoders
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: dec.c,v 1.9 2003/03/06 23:10:11 gbazin Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  28. #include <string.h>
  29.  
  30. #include <vlc/vlc.h>
  31.  
  32. #ifdef HAVE_ALLOCA_H
  33. #   include <alloca.h>
  34. #endif
  35.  
  36. #include "audio_output.h"
  37. #include "aout_internal.h"
  38. #include <vlc/input.h>                 /* for input_thread_t and i_pts_delay */
  39.  
  40. /*
  41.  * Creation/Deletion
  42.  */
  43.  
  44. /*****************************************************************************
  45.  * aout_DecNew : create a decoder
  46.  *****************************************************************************/
  47. static aout_input_t * DecNew( vlc_object_t * p_this, aout_instance_t * p_aout,
  48.                               audio_sample_format_t * p_format )
  49. {
  50.     aout_input_t * p_input;
  51.     input_thread_t * p_input_thread;
  52.  
  53.     /* We can only be called by the decoder, so no need to lock
  54.      * p_input->lock. */
  55.     vlc_mutex_lock( &p_aout->mixer_lock );
  56.  
  57.     if ( p_aout->i_nb_inputs >= AOUT_MAX_INPUTS )
  58.     {
  59.         msg_Err( p_aout, "too many inputs already (%d)", p_aout->i_nb_inputs );
  60.         return NULL;
  61.     }
  62.  
  63.     p_input = malloc(sizeof(aout_input_t));
  64.     if ( p_input == NULL )
  65.     {
  66.         msg_Err( p_aout, "out of memory" );
  67.         return NULL;
  68.     }
  69.  
  70.     vlc_mutex_init( p_aout, &p_input->lock );
  71.  
  72.     p_input->b_changed = 0;
  73.     p_input->b_error = 1;
  74.     aout_FormatPrepare( p_format );
  75.     memcpy( &p_input->input, p_format,
  76.             sizeof(audio_sample_format_t) );
  77.  
  78.     p_aout->pp_inputs[p_aout->i_nb_inputs] = p_input;
  79.     p_aout->i_nb_inputs++;
  80.  
  81.     if ( p_aout->mixer.b_error )
  82.     {
  83.         int i;
  84.  
  85.         if ( var_Type( p_aout, "audio-device" ) != 0 )
  86.         {
  87.             var_Destroy( p_aout, "audio-device" );
  88.         }
  89.         if ( var_Type( p_aout, "audio-channels" ) != 0 )
  90.         {
  91.             var_Destroy( p_aout, "audio-channels" );
  92.         }
  93.  
  94.         /* Recreate the output using the new format. */
  95.         if ( aout_OutputNew( p_aout, p_format ) < 0 )
  96.         {
  97.             for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ )
  98.             {
  99.                 vlc_mutex_lock( &p_aout->pp_inputs[i]->lock );
  100.                 aout_InputDelete( p_aout, p_aout->pp_inputs[i] );
  101.                 vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
  102.             }
  103.             vlc_mutex_unlock( &p_aout->mixer_lock );
  104.             return p_input;
  105.         }
  106.  
  107.         /* Create other input streams. */
  108.         for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ )
  109.         {
  110.             vlc_mutex_lock( &p_aout->pp_inputs[i]->lock );
  111.             aout_InputDelete( p_aout, p_aout->pp_inputs[i] );
  112.             aout_InputNew( p_aout, p_aout->pp_inputs[i] );
  113.             vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock );
  114.         }
  115.     }
  116.     else
  117.     {
  118.         aout_MixerDelete( p_aout );
  119.     }
  120.  
  121.     if ( aout_MixerNew( p_aout ) == -1 )
  122.     {
  123.         aout_OutputDelete( p_aout );
  124.         vlc_mutex_unlock( &p_aout->mixer_lock );
  125.         return NULL;
  126.     }
  127.  
  128.     aout_MixerNew( p_aout );
  129.  
  130.     aout_InputNew( p_aout, p_input );
  131.  
  132.     vlc_mutex_unlock( &p_aout->mixer_lock );
  133.  
  134.     p_input_thread = (input_thread_t *)vlc_object_find( p_this,
  135.                                            VLC_OBJECT_INPUT, FIND_PARENT );
  136.     if( p_input_thread )
  137.     {
  138.         p_aout->i_pts_delay = p_input_thread->i_pts_delay;
  139.         vlc_object_release( p_input_thread );
  140.     }
  141.     else
  142.     {
  143.         p_aout->i_pts_delay = DEFAULT_PTS_DELAY;
  144.     }
  145.  
  146.     return p_input;
  147. }
  148.  
  149. aout_input_t * __aout_DecNew( vlc_object_t * p_this,
  150.                               aout_instance_t ** pp_aout,
  151.                               audio_sample_format_t * p_format )
  152. {
  153.     if ( *pp_aout == NULL )
  154.     {
  155.         /* Create an audio output if there is none. */
  156.         *pp_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
  157.  
  158.         if( *pp_aout == NULL )
  159.         {
  160.             msg_Dbg( p_this, "no aout present, spawning one" );
  161.  
  162.             *pp_aout = aout_New( p_this );
  163.             /* Everything failed, I'm a loser, I just wanna die */
  164.             if( *pp_aout == NULL )
  165.             {
  166.                 return NULL;
  167.             }
  168.         }
  169.         else
  170.         {
  171.             vlc_object_release( *pp_aout );
  172.         }
  173.     }
  174.  
  175.     return DecNew( p_this, *pp_aout, p_format );
  176. }
  177.  
  178. /*****************************************************************************
  179.  * aout_DecDelete : delete a decoder
  180.  *****************************************************************************/
  181. int aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input )
  182. {
  183.     int i_input;
  184.  
  185.     /* This function can only be called by the decoder itself, so no need
  186.      * to lock p_input->lock. */
  187.     vlc_mutex_lock( &p_aout->mixer_lock );
  188.  
  189.     for ( i_input = 0; i_input < p_aout->i_nb_inputs; i_input++ )
  190.     {
  191.         if ( p_aout->pp_inputs[i_input] == p_input )
  192.         {
  193.             break;
  194.         }
  195.     }
  196.  
  197.     if ( i_input == p_aout->i_nb_inputs )
  198.     {
  199.         msg_Err( p_aout, "cannot find an input to delete" );
  200.         return -1;
  201.     }
  202.  
  203.     /* Remove the input from the list. */
  204.     memmove( &p_aout->pp_inputs[i_input], &p_aout->pp_inputs[i_input + 1],
  205.              (AOUT_MAX_INPUTS - i_input - 1) * sizeof(aout_input_t *) );
  206.     p_aout->i_nb_inputs--;
  207.  
  208.     aout_InputDelete( p_aout, p_input );
  209.  
  210.     vlc_mutex_destroy( &p_input->lock );
  211.     free( p_input );
  212.  
  213.     if ( !p_aout->i_nb_inputs )
  214.     {
  215.         aout_OutputDelete( p_aout );
  216.         aout_MixerDelete( p_aout );
  217.         if ( var_Type( p_aout, "audio-device" ) != 0 )
  218.         {
  219.             var_Destroy( p_aout, "audio-device" );
  220.         }
  221.         if ( var_Type( p_aout, "audio-channels" ) != 0 )
  222.         {
  223.             var_Destroy( p_aout, "audio-channels" );
  224.         }
  225.     }
  226.  
  227.     vlc_mutex_unlock( &p_aout->mixer_lock );
  228.  
  229.     return 0;
  230. }
  231.  
  232.  
  233. /*
  234.  * Buffer management
  235.  */
  236.  
  237. /*****************************************************************************
  238.  * aout_DecNewBuffer : ask for a new empty buffer
  239.  *****************************************************************************/
  240. aout_buffer_t * aout_DecNewBuffer( aout_instance_t * p_aout,
  241.                                    aout_input_t * p_input,
  242.                                    size_t i_nb_samples )
  243. {
  244.     aout_buffer_t * p_buffer;
  245.     mtime_t duration;
  246.  
  247.     vlc_mutex_lock( &p_input->lock );
  248.  
  249.     if ( p_input->b_error )
  250.     {
  251.         vlc_mutex_unlock( &p_input->lock );
  252.         return NULL;
  253.     }
  254.  
  255.     duration = (1000000 * (mtime_t)i_nb_samples) / p_input->input.i_rate;
  256.  
  257.     /* This necessarily allocates in the heap. */
  258.     aout_BufferAlloc( &p_input->input_alloc, duration, NULL, p_buffer );
  259.     p_buffer->i_nb_samples = i_nb_samples;
  260.     p_buffer->i_nb_bytes = i_nb_samples * p_input->input.i_bytes_per_frame
  261.                               / p_input->input.i_frame_length;
  262.  
  263.     /* Suppose the decoder doesn't have more than one buffered buffer */
  264.     p_input->b_changed = 0;
  265.  
  266.     vlc_mutex_unlock( &p_input->lock );
  267.  
  268.     if ( p_buffer == NULL )
  269.     {
  270.         msg_Err( p_aout, "NULL buffer !" );
  271.     }
  272.     else
  273.     {
  274.         p_buffer->start_date = p_buffer->end_date = 0;
  275.     }
  276.  
  277.     return p_buffer;
  278. }
  279.  
  280. /*****************************************************************************
  281.  * aout_DecDeleteBuffer : destroy an undecoded buffer
  282.  *****************************************************************************/
  283. void aout_DecDeleteBuffer( aout_instance_t * p_aout, aout_input_t * p_input,
  284.                            aout_buffer_t * p_buffer )
  285. {
  286.     aout_BufferFree( p_buffer );
  287. }
  288.  
  289. /*****************************************************************************
  290.  * aout_DecPlay : filter & mix the decoded buffer
  291.  *****************************************************************************/
  292. int aout_DecPlay( aout_instance_t * p_aout, aout_input_t * p_input,
  293.                   aout_buffer_t * p_buffer )
  294. {
  295.     if ( p_buffer->start_date == 0 )
  296.     {
  297.         msg_Warn( p_aout, "non-dated buffer received" );
  298.         aout_BufferFree( p_buffer );
  299.         return -1;
  300.     }
  301.  
  302.     if ( p_buffer->start_date > mdate() + p_aout->i_pts_delay +
  303.          AOUT_MAX_ADVANCE_TIME )
  304.     {
  305.         msg_Warn( p_aout, "received buffer in the future ("I64Fd")",
  306.                   p_buffer->start_date - mdate());
  307.         aout_BufferFree( p_buffer );
  308.         return -1;
  309.     }
  310.  
  311.     p_buffer->end_date = p_buffer->start_date
  312.                             + (mtime_t)(p_buffer->i_nb_samples * 1000000)
  313.                                 / p_input->input.i_rate;
  314.  
  315.     vlc_mutex_lock( &p_input->lock );
  316.  
  317.     if ( p_input->b_error )
  318.     {
  319.         vlc_mutex_unlock( &p_input->lock );
  320.         aout_BufferFree( p_buffer );
  321.         return -1;
  322.     }
  323.  
  324.     if ( p_input->b_changed )
  325.     {
  326.         /* Maybe the allocation size has changed. Re-allocate a buffer. */
  327.         aout_buffer_t * p_new_buffer;
  328.         mtime_t duration = (1000000 * (mtime_t)p_buffer->i_nb_samples)
  329.                             / p_input->input.i_rate;
  330.  
  331.         aout_BufferAlloc( &p_input->input_alloc, duration, NULL, p_new_buffer );
  332.         p_aout->p_vlc->pf_memcpy( p_new_buffer->p_buffer, p_buffer->p_buffer,
  333.                                   p_buffer->i_nb_bytes );
  334.         p_new_buffer->i_nb_samples = p_buffer->i_nb_samples;
  335.         p_new_buffer->i_nb_bytes = p_buffer->i_nb_bytes;
  336.         p_new_buffer->start_date = p_buffer->start_date;
  337.         p_new_buffer->end_date = p_buffer->end_date;
  338.         aout_BufferFree( p_buffer );
  339.         p_buffer = p_new_buffer;
  340.         p_input->b_changed = 0;
  341.     }
  342.  
  343.     /* If the buffer is too early, wait a while. */
  344.     mwait( p_buffer->start_date - AOUT_MAX_PREPARE_TIME );
  345.  
  346.     if ( aout_InputPlay( p_aout, p_input, p_buffer ) == -1 )
  347.     {
  348.         vlc_mutex_unlock( &p_input->lock );
  349.         return -1;
  350.     }
  351.  
  352.     vlc_mutex_unlock( &p_input->lock );
  353.  
  354.     /* Run the mixer if it is able to run. */
  355.     vlc_mutex_lock( &p_aout->mixer_lock );
  356.     aout_MixerRun( p_aout );
  357.     vlc_mutex_unlock( &p_aout->mixer_lock );
  358.  
  359.     return 0;
  360. }
  361.